<?php

namespace app\service;

use FFMpeg\Coordinate\Dimension;
use FFMpeg\FFMpeg;
use FFMpeg\FFProbe;
use FFMpeg\Filters\Video\ResizeFilter;
use FFMpeg\Format\Audio\Wav;
use FFMpeg\Format\Video\X264;
use FFMpeg\Coordinate\TimeCode;

/*
 * 音频格式转换（语音转文字需要）
 *
 */
class FFmpegService {
    /**
     * @return mixed
     */
    public function app() {
        $config = [
            'ffmpeg.binaries'  => 'C:/ffmpeg-2022-09-15-git-3f0fac9303-essentials_build/bin/ffmpeg.exe',
            'ffprobe.binaries' => 'C:/ffmpeg-2022-09-15-git-3f0fac9303-essentials_build/bin/ffprobe.exe',
            'timeout'          => 3600,
            'ffmpeg.threads'   => 12,
        ];

        $os_name = PHP_OS;
        if (strpos($os_name, "Linux") !== false) {
            $config['ffmpeg.binaries']  = '/usr/bin/ffmpeg';
            $config['ffprobe.binaries'] = '/usr/bin/ffprobe';
        }
        return $ffmpeg = FFMpeg::create($config);
    }
    public function FFProbeApp() {
        $config = [
            'ffmpeg.binaries'  => 'C:/ffmpeg-2022-09-15-git-3f0fac9303-essentials_build/bin/ffmpeg.exe',
            'ffprobe.binaries' => 'C:/ffmpeg-2022-09-15-git-3f0fac9303-essentials_build/bin/ffprobe.exe',
            'timeout'          => 3600,
            'ffmpeg.threads'   => 12,
        ];

        $os_name = PHP_OS;
        if (strpos($os_name, "Linux") !== false) {
            $config['ffmpeg.binaries']  = '/usr/bin/ffmpeg';
            $config['ffprobe.binaries'] = '/usr/bin/ffprobe';
        }
        return $ffprobe = FFProbe::create($config);
    }
    public static function videoInfo($videoPath)
    {
        $app = (new FFmpegService)->FFProbeApp();
        $audioInfo = $app->streams($videoPath)->audios()->first();
        $videoInfo = $app->streams($videoPath)->videos()->first();
        $data['width'] = $videoInfo->get('width');
        $data['height'] = $videoInfo->get('height');
        $data['duration'] = $videoInfo->get('duration');
        $data['vbit'] = intval($videoInfo->get('bit_rate') / 1024);
        $data['abit'] = intval($audioInfo->get('bit_rate') / 1024);
        $fileSizeBytes = filesize($videoPath);
        $data['filesize'] = number_format($fileSizeBytes / (1024 * 1024), 2);
        return $data;
    }

    /**
     * @param $audio
     * @param $savepath
     * @return mixed
     */
    public static function FormatWav($audio, $savepath) {
        try {
            $ffmpeg = (new FFmpegService)->app();
            $audio  = $ffmpeg->open($audio);
            $wav    = new Wav();
            $wav->setAudioChannels(1);
            $audio->filters()->resample('8000');
            $audio->save($wav, $savepath);
            return $savepath;
        } catch (\Exception $e) {
            return false;
        }
    }

    /* 视频压缩 */
    /* 缺少库，暂不可用 */
    /**
     * @param $path
     * @param $savepath
     * @return mixed
     */
    public static function reduceVideo($path = '', $savepath = '') {
        try {
            $ffmpeg = (new FFmpegService)->app();
            $video  = $ffmpeg->open($path);
            $video->filters()->resize(new Dimension(400, 400), ResizeFilter::RESIZEMODE_INSET, true);
            $video->save(new X264('libfdk_aac'), $savepath);
            return $savepath;
        } catch (\Exception $e) {
            return false;
        }
    }

    /* 视频压缩 */
    /**
     * @param $file
     * @param $file_name
     */
    public static function compressVideo($compress_file, $compress_after_file) {
        try {
            $video_info;
            exec("ffmpeg -i {$compress_file} 2>&1", $video_info);
            $video_info = implode(' ', $video_info);
            $bitrate    = ''; // 比特率
            $resolution = ''; // 分辨率
            if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $video_info, $match)) {
                $bitrate = $match[3];
            }

            preg_match('/(\d{3,4}x\d{3,4})/', $video_info, $resolutionmatches);
            $resolution = $resolutionmatches[0];
            // if (preg_match("/Video: (.*?), (.*?), (.*?)[,\s]/", $video_info, $match)) {
                // $resolution = $match[3];
            // }
            
            $file_size = filesize($compress_file);
            $file_size = intval($file_size / 1048576);
            if (empty($bitrate)) {
            	return '';
                var_dump('找不到比特率信息');exit;
            }

            if (empty($resolution)) {
            	return '';
                var_dump('找不到分辨率信息');exit;
            }

            if ($file_size < 4) {
            	return '';
                var_dump('视频大小不足4M，不需要压缩');exit;
            }

            $resolution               = explode('x', $resolution);
            $bitrate_update           = '';
            $resolution_width_update  = '';
            $resolution_height_update = '';
            $bitrate_update           = self::getVideoCompressBitrate($bitrate);
            $resolution_percent       = 0;
            if ($resolution[0] > $resolution[1]) {
                if ($resolution[1] > 320) {
                    $resolution_percent = $resolution[1] <= 720 ? 0.8 : 0.5;
                }
            } else {
                if ($resolution[0] > 320) {
                    $resolution_percent = $resolution[0] <= 720 ? 0.8 : 0.5;
                }
            }
            if ($resolution_percent > 0) {
                $resolution_width_update  = intval($resolution[0] * $resolution_percent);
                $resolution_height_update = intval($resolution[1] * $resolution_percent);
            }
            if (empty($bitrate_update) && empty($resolution_width_update)) {
            	return '';
                var_dump('比特率和分辨率同时不满足压缩条件', null, 1100);exit;
            }

            $compress_bitrate    = '';
            $compress_resolution = '';
            if (!empty($bitrate_update)) {
                $compress_bitrate = "-b:v {$bitrate_update}k";
            }
            if (!empty($resolution_width_update)) {
                $compress_resolution = "-s {$resolution_width_update}x{$resolution_height_update}";
            }
            $compress_exec = "ffmpeg -i {$compress_file} %s% %v% {$compress_after_file}";
            $compress_exec = str_replace(['%s%', '%v%'], [$compress_resolution, $compress_bitrate], $compress_exec);
            // var_dump($compress_exec);exit;
            exec($compress_exec);

            return $compress_after_file;
        } catch (\Exception $e) {
        	return '';
            var_dump($e->getMessage());exit;
        }
    }

	/* 获取视频压缩比特率 */
    /**
     * @param $bitrate
     * @param $query_count
     * @return mixed
     */
    public static function getVideoCompressBitrate($bitrate, $query_count = 0) {
        $bitrate_update = '';
        if ($bitrate >= 700) {
            if ($bitrate <= 1000) {
                $bitrate_update = intval($bitrate * 0.8);
            } else {
                $bitrate_update = intval($bitrate * 0.5);
            }
        }
        if (empty($bitrate_update)) {
            return $query_count == 0 ? $bitrate_update : $bitrate;
        } else {
            return self::getVideoCompressBitrate($bitrate_update, ++$query_count);
        }
    }

    public static function convertAndCompressVideoToM3U8($videoUrl){
        $videoPathInfo = pathinfo($videoUrl);
        $videoDirectory = $videoPathInfo['dirname'];
        $videoFileName = $videoPathInfo['filename'];
        $compress_file = $videoUrl;
        $fileName = $videoDirectory . '/' . $videoFileName . '/'.$videoFileName.'.m3u8';

        $folderPath = $videoDirectory . '/' . $videoFileName;
        if (!file_exists($folderPath)) {
            // 检查目录是否存在，如果不存在则创建
            if (mkdir($folderPath, 0777, true)) {
            } else {
                return false;
            }
        }

        $videoInfo = self::videoInfo($videoUrl);

        $videoBitrate = $videoInfo['vbit'];
        $audioBitrate = $videoInfo['abit'];
        $videoBitrate /= 1.6;
        $audioBitrate /= 1.6;


        if ($videoInfo['filesize'] > 5) {
            $compress_exec = "nice -n 10 ffmpeg -threads 2 -i {$compress_file} -c:v libx264 -crf 23 -preset medium -c:a aac -hls_time 4 -hls_list_size 0 {$fileName} 2>&1";
        } else {
            $compress_exec = "nice -n 10 ffmpeg -threads 2 -i {$compress_file} -c:v libx264 -b:v {$videoBitrate}k -c:a aac -b:a ${audioBitrate}k -hls_time 4 -hls_list_size 0 {$fileName} 2>&1";
        }

        // var_dump($compress_exec);exit;
        $output;
        exec($compress_exec, $output);

        return $fileName;
    }
}